/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package gride.plugin.compiler;

import gride.GrideSettings;
import gride.events.EventListener;
import gride.events.GrideEvents;
import gride.plugin.GridePlugin;
import gride.project.GrideScript;
import gride.project.Project;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;

/**
 *
 * @author lukasz
 */
public class CompilerPlugin extends GridePlugin
{
    // <editor-fold defaultstate="expanded" desc="Private Members">

    GridePlugin self = this;

    JMenuItem compileMenuItem;
    JMenuItem compileAllMenuItem;

    // </editor-fold>


    // <editor-fold defaultstate="expanded" desc="Constructors">

    /**
     *
     */
    public CompilerPlugin()
    {
        InitializeGUI();
    }

    private void InitializeGUI() {
        compileMenuItem = new JMenuItem("Compile");
        compileMenuItem.addActionListener(new CompileListener());
        compileAllMenuItem = new JMenuItem("Compile All");
        compileAllMenuItem.addActionListener(new CompileAllListener());
    }

    // </editor-fold>

    // <editor-fold defaultstate="expanded" desc="Actions">

    private void compileAction()
    {
        GrideScript script = projectManager.getActiveFile();

        if (script != null)
        {
            eventManager.raiseEvent(GrideEvents.SAVE_ALL_FILES, null);

            if (runGroovyc(script.getFullName().replace(".", "/") + ".groovy"))
            {
                // compilation successful - set script's class file
                String buildPath =
                        projectManager.getCurrentProject().getBuildDir() + "/" +
                        script.getFullName().replace(".", "/") + ".class";
                script.setClassFile(new File(buildPath));
            }
        }
    }

    private void compileAllAction()
    {
        Project project = projectManager.getCurrentProject();

        if (project != null)
        {
            eventManager.raiseEvent(GrideEvents.SAVE_ALL_FILES, null);

            String files = "";

            for (GrideScript script : project.getScripts())
                files += script.getFullName().replace(".", "/") + ".groovy ";

            if (runGroovyc(files))
            {
                // compilation successful - set class files for all scripts
                for (GrideScript script : project.getScripts())
                {
                    String buildPath =
                        projectManager.getCurrentProject().getBuildDir() + "/" +
                        script.getFullName().replace(".", "/") + ".class";
                    script.setClassFile(new File(buildPath));
                }
            }
        }
    }

    // </editor-fold>

    // <editor-fold defaultstate="expanded" desc="Plugin (De)activation">

    /**
     * 
     */
    @Override
    public void activate() 
    {
        guiManager.addMenuItem(compileMenuItem, "Compile");
        guiManager.addMenuItem(compileAllMenuItem, "Compile");
        setMenuItemsStatus();

        eventManager.addListener(GrideEvents.ACTIVE_FILE_CHANGED,
                                 new MenuItemsStatusListener());
        eventManager.addListener(GrideEvents.PROJECT_CLOSED,
                                 new MenuItemsStatusListener());
        eventManager.addListener(GrideEvents.PROJECT_LOADED,
                                 new MenuItemsStatusListener());

        active = true;
    }

    /**
     *
     */
    @Override
    public void deactivate()
    {
        guiManager.removeMenuItem(compileMenuItem);
        guiManager.removeMenuItem(compileAllMenuItem);

        eventManager.removeAllListenersFrom(this);

        active = false;
    }

    // </editor-fold>    

    // <editor-fold defaultstate="expanded" desc="Private Methods">

    private boolean runGroovyc(String files)
    {
        Project project = projectManager.getCurrentProject();

        String command = GrideSettings.GROOVY_HOME_DIR + "/bin/groovyc " + 
                  "-d " + project.getBuildDir().getAbsolutePath() + " " + files;

        String[] envp = { "GROOVY_HOME=" + GrideSettings.GROOVY_HOME_DIR,
                          "JAVA_HOME=" + GrideSettings.JAVA_HOME_DIR };

        Runtime runtime = Runtime.getRuntime();

        try
        {
            Process p = runtime.exec(command, envp,
                                     project.getSourceDir().getAbsoluteFile());

            BufferedReader stdError = new BufferedReader(new
                 InputStreamReader(p.getErrorStream()));

            String line = null;
            String errOutput = "";

            // read any errors from the attempted command
            while ((line = stdError.readLine()) != null)
                errOutput += line;

            // if there were errors, generate a COMPILATION_ERROR event
            if (!errOutput.equals(""))
            {
                Object[] args = { errOutput };
                eventManager.raiseEvent(GrideEvents.COMPILATION_ERROR, args);
                return false;
            }
        }
        catch (IOException e)
        {
            JOptionPane.showMessageDialog(null, "IO Error during compilation: "
                          + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
            return false;
        }

        // compilation successful - display message
        JOptionPane.showMessageDialog(null, "Scripts successfuly compiled to " +
           "Java bytecode. \nClass files generated in " + project.getBuildDir(),
           "Compilation finished", JOptionPane.INFORMATION_MESSAGE);

        return true;
    }

    private void setMenuItemsStatus()
    {
        boolean compile = false;
        boolean compileAll = false;

        Project project = projectManager.getCurrentProject();

        if (project != null)
        {
            compile = (projectManager.getActiveFile() != null);
            compileAll = (project.getScripts().size() > 0);
        }

        compileMenuItem.setEnabled(compile);
        compileAllMenuItem.setEnabled(compileAll);
    }

    // </editor-fold>

    // <editor-fold defaultstate="expanded" desc="Listener classes">

    private class CompileListener implements ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            compileAction();
        }
    }

    private class CompileAllListener implements ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            compileAllAction();
        }
    }

    private class MenuItemsStatusListener implements EventListener
    {
        public Object whoIsListening()
        {
            return self;
        }

        public void eventRaised(String eventID, Object[] args)
        {
            setMenuItemsStatus();
        }
    }

    // </editor-fold>

}
